package com.zhixinglu.spring.boot.generator.nickname.configure;

import org.redisson.api.RAtomicLong;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * UniqueNicknameGenerator
 * </p>
 *
 * @author weixin
 * @date 2023/3/27 10:59
 */
@Component
public class UniqueNicknameGenerator {

    private static final int MAX_ATTEMPTS = 10;
    private static final int NICKNAME_LENGTH = 6;
    private static final char[] CHARACTERS = "abcdefghijklmnopqrstuvwxyz".toCharArray();
    private static final Random RANDOM = new Random();
    private static final String COUNTER_KEY = "nickname_counter";

    private final RedissonClient redissonClient;
    private final RAtomicLong nicknameCounter;

    @Autowired
    public UniqueNicknameGenerator(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
        this.nicknameCounter = redissonClient.getAtomicLong(COUNTER_KEY);
        this.nicknameCounter.compareAndSet(0, 1000000);
    }

    public String generateNickname() {
        RLock lock = redissonClient.getLock("nickname_lock");
        try {
            boolean locked = lock.tryLock(500, 2000, TimeUnit.MILLISECONDS);
            if (!locked) {
                throw new RuntimeException("Failed to acquire nickname lock");
            }

            int attempts = 0;
            while (attempts < MAX_ATTEMPTS) {
                String nickname = generateRandomNickname();
                if (isNicknameUnique(nickname)) {
                    return nickname;
                }
                attempts++;
            }

            throw new RuntimeException("Failed to generate unique nickname after " + MAX_ATTEMPTS + " attempts");
        } catch (InterruptedException e) {
            throw new RuntimeException("Interrupted while acquiring nickname lock", e);
        } finally {
            lock.unlock();
        }
    }

    private String generateRandomNickname() {
        StringBuilder sb = new StringBuilder(NICKNAME_LENGTH);
        for (int i = 0; i < 3; i++) {
            sb.append(CHARACTERS[RANDOM.nextInt(CHARACTERS.length)]);
        }
        sb.append(nicknameCounter.incrementAndGet());
        return sb.toString();
    }

    private boolean isNicknameUnique(String nickname) {
        // Check if nickname already exists in database or cache
        return true;
    }

}
